home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / admin / fbackup < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  19.1 KB  |  677 lines

  1. #!/bin/ksh
  2. # @(#) fbackup.ksh 4.5 97/01/06
  3. # Make backup list before feeding it to cpio to help tape drive stream.
  4. # XENIX 2.3.2 tape driver hangs if written with much more than 64K at a time.
  5. # cpio allocates 2-10 times the given buffer size (as much as it can,
  6. # up to 10 times).
  7. # 91/05/04 john h. dubois iii (john@armory.com)
  8. # 91/06/11 change find cmd to generate relative pathnames
  9. # 91/06/14 changed buffer size to 65536
  10. # 91/10/24 added 'a' option to cpio so we can tell how long it's been since
  11. #          someone used a file, and V to indicate progression of backup
  12. # 91/12/11 added -K 150000 to cpio options
  13. # 92/03/21 Use -mount option; back up selected fs
  14. # 92/07/01 Allow tapesize to be given on cmd line
  15. # 92/07/10 Don't backup #files or corefiles
  16. # 94/10/03 Make tape size of 0 mean no limit.  Added s and l options.
  17. # 94/12/04 Added fhnorx options.  Modified to do multi-filesystem backup.
  18. # 94/12/09 Added t option.
  19. # 94/12/14 Fixed BLOCKSIZE use.
  20. # 94/12/30 Allow a prepared filelist to be given for each filesystem.
  21. # 95/02/12 Added w option.
  22. # 95/03/06 Renamed to avoid confusion with /usr/lib/sysadmin/cbackup.
  23. # 95/05/27 Give parameters to slow in the correct units.
  24. # 95/08/31 Added c option.  Not tested yet.
  25. # 96/01/20 Make tmpfile more carefully.
  26. # 96/02/06 Added generation of control device name
  27. # 96/02/13 Added p option.
  28. # 96/03/27 Make TAPESIZE 0 by default.
  29. # 96/04/09 Try both rct0 and rStp0
  30. # 96/04/15 Get defaults from /etc/default/fbackup.  Check remote backups too.
  31. #          Added S option.
  32. # 96/06/19 Added C option.
  33. # 96/06/21 Write status to logfile.  Added L option.  Print tape amount info.
  34. # 96/06/23 Let -S be given without -t.  Rewind before backup.  Added N option.
  35. # 96/06/28 Use coprocess for logger.  Added g option.
  36. # 96/07/12 Make coprocess output to stdout properly.
  37. # 97/01/06 Added dD options.
  38.  
  39. set -A Args -- "$@"    # Save args because set -A loses them in some versions
  40. set -A rDevs /dev/r{ct,Stp}0 
  41. set -A nrDevs /dev/nr{ct,Stp}0 
  42. set -- "${Args[@]}"    # Restore args
  43. ControlDev=
  44. deftape=0
  45. DEVICE=
  46. lname=${0##*/}
  47. filelist=/tmp/#bk.$$.{}
  48. PrepList=false
  49. debug=false
  50. rVerify=false
  51. TestTape=false
  52. CheckOnly=false
  53. logfile=
  54. # Typical kernel tape buffer size size, which is the largest size the DAT
  55. # driver will accept.
  56. typeset -i DefBlockSize=64 NumGood=0 BLOCKSIZE TAPESIZE=-1 WRITERATE=0
  57. REMOTE=
  58. CHECK=
  59. PRESERVELISTS=
  60. NOLOG=
  61. NOREWIND=
  62. CPIOPATH=cpio
  63. defaultFile=/etc/default/fbackup
  64. Usage=\
  65. "Usage: $lname [-cChNptS] [-f<find-options>] [-r<remote-system[:remote-user]>]
  66.               [-o<device>] [-l<filename>] [-s<tapesize>] [-g<logfile-name>]
  67.           [-b<blocksize>] [-w<write-rate>] [-[dD]<cpio-path>] <fs-root> ..."
  68.  
  69.  
  70. [ -f $defaultFile -a -r $defaultFile ] && . $defaultFile
  71.  
  72. while getopts cChpl:Ls:o:f:nNxr:tb:w:Sg:d:D: opt "$@"; do
  73.     case $opt in
  74.     h)
  75.     print -r -- \
  76. "$lname: Make cpio backups of filesystems on tape.
  77. $Usage
  78. If more than one filesystem-root is given, they are stored in seperate cpio
  79. archives on the tape, with filemarks between them.  This is achieved by using
  80. the no-rewind tape device (${nrDevs[0]}, or if it does not exist, ${nrDevs[1]})
  81. and closing and opening the device between extents.  All filesystems must be
  82. mounted to be backed up.  find is always given the -mount option, so only files
  83. on the same filesystems as the <fs-root> arguments are backed up.
  84. For each archive, a status line giving the amount of data written to tape is
  85. printed.  The same information is written to a logfile named /tmp/#fbackup.pid,
  86. where pid is the process ID of the program. 
  87. Options:
  88. The defaults for some of the following options can be set by assigning values
  89. to variables in the file $defaultFile, in the form
  90. VARNAME=value
  91. For options that do not take a value, use
  92. VARNAME=1
  93. The variable names are given in parentheses after the option descriptions.
  94. -h: Print this help.
  95. -c: Check backups after they are written.  This does not work with multivolume
  96.     tape backups, or backups appended to a tape.  The same blocksize used to
  97.     write the tape is used to read it.  It is read at full speed regardless of
  98.     what the write-rate is set to.  (CHECK)
  99. -C: Check an already-written backup.  The number of filesystem-root names given
  100.     on the backup determines how many tape extents are checked.  However, the
  101.     filesystem-roots need not exist.
  102. -f<find-options>: Pass the given options to find, to restrict the files
  103.     archived.  If more than one word is used, they should be quoted. (FINDOPTS)
  104. -N: Do not rewind the tape before writing to it.
  105. -o<device>: Write output to device <device>, instead of the default device
  106.     (${rDevs[0]} or ${rDevs[1]} if a single filesystem is being backed up, or
  107.     ${nrDevs[0]} or ${nrDevs[1]} if multiple filesystems are being backed up). 
  108.     If multiple filesystems are to be backed up, be sure to give a device which
  109.     does not rewind when closed.  Use a device name of '-' to write to the
  110.     standard output.  The name of the control device will be determined by
  111.     replacing everything up through a leading 'r' in the trailing component of
  112.     the device name with 'x'; e.g., the control devices for /dev/nurStp0 and
  113.     /dev/rct0 would be /dev/xStp0 and /dev/xct0 respectively.  If the control
  114.     device does not exist, the read/write device is used instead.  (DEVICE)
  115. -p: Preserve file lists (in /tmp/#bk.pid.fs-name).  (PRESERVELISTS)
  116. -s<tapesize>: Set the size of the tape media to <tapesize> KB.  The default is
  117.     0, which causes $lname to write to the end of the media.  If multiple
  118.     filesystems are given or backup is being done to a drive on a remote
  119.     system, a tapesize of 0 is always used, since only individual cpio sessions
  120.     keep track of tape size and the rcmd pipe cannot be reopened.  (TAPESIZE)
  121. -b<blocksize>: Set the size of blocks written to the tape device (this does not
  122.     affect the size of blocks as they appear on tape).  <blocksize> is given in
  123.     kilobytes.  The default is $DefBlockSize.  (BLOCKSIZE)
  124. -l<filename>: Take a list of files to be backed up from <filename> instead of
  125.     generating a list.  If the filename is relative (does not start with /),
  126.     it is taken to be relative to the filesystem mount point.  If the name
  127.     includes the string '{}', the {} is replaced by the trailing part of the
  128.     mount point path, except that if the mount point is /, it is replaced with
  129.     'root'.  The default filename is is /tmp/#bk.pid.{}, where pid is the
  130.     process ID of the backup program, so that the filelist for e.g. /u might be
  131.     stored in /tmp/#bk.12045.u.  Unless -l is given, any prexisting file is
  132.     overwritten.
  133. -L: Do not create or write to the logfile.  (NOLOG)
  134. -g<logfile-name>: Write to <logfile-name> instead of the default log file.
  135. -n: Use the no-rewind tape device (${nrDevs[0]} or ${nrDevs[1]}).  (NRDEVICE)
  136. -r<remote-system[:remote-user]>: Use rcmd to back up onto a tape drive on a
  137.     remote system.  If a : and a user name are appended to the system name,
  138.     $lname attempt to execute the dd command that is used to write to tape as
  139.     that user on the remote system; if not, it attempts to execute the command
  140.     as the same user as the one running $lname.  Whatever user the remote
  141.     command is run as, that user must have user equivalency for the same user
  142.     on the local system.  (REMOTE)
  143. -t: Used only with -r.  Instead of being written to a tape device, the cpio
  144.     stream is piped through cpio -it on the remote system (without writing
  145.     anything to disk) to test the archive integrity after it has crossed
  146.     the network.
  147. -S: Check status and accessibility of local or remote tape control device with
  148.     'tape status'.
  149. -d<cpio-path>: Use <cpio-path> as the cpio command.  The default is to use
  150.     \"cpio\" wherever it exists in the command search path.  (CPIOPATH)
  151. -D<cpio-path>: Use <cpio-path> as the cpio used to test archive integrity.
  152.     This path is used on the remote system if -t is given, or -c or -C is used
  153.     with -r.  (TCPIOPATH)
  154. -w<write-rate>:  Pipe the data stream through 'slow', which throttles the data
  155.     rate to <write-rate> kilobytes per second.  This can be used to reduce the
  156.     backup load on a system, or (if used with -r) to reduce the network load.
  157.     If used with -t, the 'slow' command will be run on the remote system
  158.     instead of the local system, with its output sent to cpio.  This can be
  159.     used to exercise (test) network buffers more thoroughly than -t by itself.
  160.     Use of -w requires the 'slow' command to be available on the local or, if
  161.     used with -t, the remote system.  (WRITERATE)"
  162.     exit 0
  163.     ;;
  164.     g)
  165.     logfile=$OPTARG
  166.     ;;
  167.     C)
  168.     CheckOnly=true
  169.     CHECK=1
  170.     ;;
  171.     c)
  172.     CHECK=1
  173.     ;;
  174.     l)
  175.     filelist=$OPTARG
  176.     PrepList=true
  177.     ;;
  178.     L)
  179.     NOLOG=1;;
  180.     p)
  181.     PRESERVELISTS=1
  182.     ;;
  183.     f)
  184.     FINDOPTS=$OPTARG
  185.     ;;
  186.     n)
  187.     NRDEVICE=1
  188.     ;;
  189.     b)
  190.     BLOCKSIZE=$OPTARG
  191.     # Must test exit status in a separate operation
  192.     [ $? -eq 0 ] || exit 1
  193.     ;;
  194.     s)
  195.     TAPESIZE=$OPTARG
  196.     [ $? -eq 0 ] || exit 1
  197.     ;;
  198.     w)
  199.     WRITERATE=$OPTARG
  200.     [ $? -eq 0 ] || exit 1
  201.     ;;
  202.     o)
  203.     DEVICE=$OPTARG
  204.     ;;
  205.     x)
  206.     debug=true
  207.     ;;
  208.     r)
  209.     REMOTE=$OPTARG
  210.     ;;
  211.     t)
  212.     rVerify=true
  213.     ;;
  214.     N)
  215.     NOREWIND=1
  216.     ;;
  217.     S)
  218.     TestTape=true
  219.     ;;
  220.     d)
  221.     CPIOPATH=$OPTARG
  222.     ;;
  223.     D)
  224.     TCPIOPATH=$OPTARG
  225.     ;;
  226.     ?) 
  227.     print -ru2 "Use -h for help."
  228.     exit 1
  229.     ;;
  230.     esac
  231. done
  232.  
  233. [ -z "$TCPIOPATH" ] && TCPIOPATH=$CPIOPATH
  234.  
  235. if [ -n "$REMOTE" ]; then
  236.     RemoteSys=${REMOTE%%:*}
  237.     RemoteUser=${REMOTE#*:}
  238. else
  239.     if $rVerify; then
  240.     print -ru2 "Must give system name (-r or REMOTE) with -t."
  241.     exit 1
  242.     fi
  243. fi
  244.  
  245. if [ -n "$NRDEVICE" ]; then
  246.     if [ -n "$DEVICE" ]; then
  247.     print -ru2 "Cannot give both -o (DEVICE) and -n (NRDEVICE) options."
  248.     exit 1
  249.     fi
  250.     nDev=n
  251. fi
  252.  
  253. [ BLOCKSIZE -eq 0 ] && BLOCKSIZE=DefBlockSize
  254. [ WRITERATE -gt 0 ] &&
  255. SlowCmd="slow -s ${BLOCKSIZE}k -b ${BLOCKSIZE}k ${WRITERATE}k"
  256.  
  257. # remove args that were options
  258. let OPTIND=OPTIND-1
  259. shift $OPTIND
  260.  
  261. case $# in
  262. 0)
  263.     if ! $TestTape; then
  264.     print -ru2 -- "$Usage
  265. Use -h for help."
  266.     exit
  267.     fi
  268.     ;;
  269. 1)
  270.     ;;
  271. *)
  272.     if [ TAPESIZE -gt 0 ]; then
  273.     print -ru2 -- \
  274.     "$lname: cannot give a tape size for multi-filesystem backup."
  275.     exit 1
  276.     fi
  277.     TAPESIZE=0
  278.     ;;
  279. esac
  280.  
  281. if [ -n "$REMOTE" ]; then
  282.     if [ TAPESIZE -gt 0 ]; then
  283.     print -ru2 -- "$lname: cannot give a tape size for remote backup."
  284.     exit 1
  285.     fi
  286.     TAPESIZE=0
  287.     if [ "$DEVICE" = - ]; then
  288.     print -ru2 -- "$lname: cannot write to stdout for remote backup."
  289.     exit 1
  290.     fi
  291.     if [ -n "$RemoteUser" ]; then
  292.     UserArg="-l $RemoteUser"
  293.     else
  294.     UserArg=
  295.     fi
  296. fi
  297.  
  298. # Select devices to try
  299. if [ -z "$DEVICE" ]; then
  300.     [ $# -eq 1 ] && set -A Devs "${rDevs[@]}" || set -A Devs "${nrDevs[@]}"
  301. else
  302.     set -A Devs -- "$DEVICE"    # make this the only device in list
  303. fi
  304.  
  305. if [ -z "$REMOTE" -a "$DEVICE" != - ]; then
  306.     for DEVICE in "${Devs[@]}"; do
  307.     [ -c "$DEVICE" ] && break
  308.     done
  309.     if [ ! -c "$DEVICE" ]; then
  310.     print -ru2 -- "No character device in: ${Devs[*]}.  Exiting."
  311.     exit 1
  312.     fi
  313. fi
  314.  
  315. # Check these before we begin backing up any filesystems
  316. if ! $CheckOnly; then
  317.     for dir; do
  318.     if [ ! -d "$dir" ]; then
  319.         print -ru2 -- "$dir is not a directory.  Exiting."
  320.         exit 1
  321.     fi
  322.     if [ ! -x "$dir" ]; then
  323.         print -ru2 -- "Cannot execute directory $dir.  Exiting."
  324.         exit 1
  325.     fi
  326.     done
  327. fi
  328.  
  329. [ TAPESIZE -lt 0 ] && TAPESIZE=$deftape
  330. [ TAPESIZE -eq 0 ] && TapeSizeOpt= || TapeSizeOpt="-K $TAPESIZE"
  331.  
  332. if [ -n "$REMOTE" -o "$DEVICE" = - ]; then
  333.     DevArg=
  334. else
  335.     DevArg="-O $DEVICE"
  336. fi
  337.  
  338. if $debug; then
  339.     print -ru2 \
  340. "Tape Size: $TAPESIZE  
  341. Block Size: $BLOCKSIZE
  342. Write Rate: $WRITERATE
  343. filesystems: $*
  344. device: $DEVICE
  345. find options: $FINDOPTS
  346. filelist: $filelist
  347. remote system: $RemoteSys
  348. remote user: $RemoteUser
  349. Check: $CHECK
  350. Nolog: $NOLOG
  351. Preserve: $PRESERVELISTS
  352. Nrdevice: $NRDEVICE"
  353.     set -x
  354. fi
  355.  
  356. # @(#) mktempfile 1.0 96/06/22
  357. # 96/01/20 jhdiii
  358.  
  359. # Usage: mkfiles [-n] name ...
  360. # Creates the named files with some attempt at security.
  361. # This will be more reliable if user do not have chown authority.
  362. # Any file that contains no / characters is created in the user's tempdir.
  363. # If TMP was not set, it is set by this function.
  364. # The resulting filenames are put in mkfiles_ret[0..n-1]
  365. # Returns 0 on success; prints a diagnostic message & returns 1 on failure.
  366. # Options:
  367. # If -n is given, files are not put in the tempdir, and TMP is not set.
  368. # Use -- to force termination of the option list.
  369. function mkfiles {
  370.     typeset file dotmp=true
  371.     typeset -i i=0
  372.  
  373.     if [ "$1" = -n ]; then
  374.     dotmp=false
  375.     shift
  376.     else
  377.     : ${TMP:=$TMPDIR}
  378.     : ${TMP:=/tmp}
  379.     fi
  380.     if [ "$1" = -- ]; then
  381.     shift
  382.     fi
  383.     for file; do
  384.     if $dotmp; then
  385.         [[ "$file" != */* ]] && file="$TMP/$file"
  386.     fi
  387.     mkfiles_ret[i]=$file
  388.     let i+=1
  389.     done
  390.  
  391.     rm -f -- "${mkfiles_ret[@]}" || {
  392.     # hopefully rm will have printed a more specific message.
  393.     print -ru2 "Could not remove pre-existing files."
  394.     return 1
  395.     }
  396.     for file in "${mkfiles_ret[@]}"; do
  397.     # Use >> to avoid 0'ing the file in case a symlink was just made from
  398.     # the filename to something we don't want to truncate
  399.     >> "$file" || {
  400.         print -ru2 "Could not create temp file $file"
  401.         return 1
  402.     }
  403.     # These are very suspicious
  404.     [ -s "$file" ] && {
  405.         print -ru2 "New tempfile is not empty!!!"
  406.         return 1
  407.     }
  408.     [ -O "$file" ] || {
  409.         print -ru2 "Do not own $file!!!"
  410.         return 1
  411.     }
  412.     done
  413.     # Could do some more stuff here, but anyone concerned with security should
  414.     # have chown authorization off for most users.
  415.     return 0
  416. }
  417.  
  418. # Usage: mktempfile name
  419. # Creates a tempfile name tempdir/#name$$, and sets the global mktempfile_ret
  420. # to that name.  tempdir is a temp directory in $TMP, $TMPDIR, or /tmp, and $$
  421. # is the PID of the current process.
  422. # name should be 8 characters or less, so that the resulting filename will
  423. # not be more than 14 characters long (a limit on some machines).
  424. # Returns 0 on success, prints a diagnostic message & returns 1 on failure.
  425. function mktempfile {
  426.     typeset file="#$1$$"
  427.     mkfiles "$file" || return 1
  428.     mktempfile_ret=${mkfiles_ret[0]}
  429. }
  430.  
  431. typeset -i nList=0
  432. function CleanExit {
  433.     [ nList -gt 0 ] && rm -f -- "${fLists[@]}"
  434.     exit "$1"
  435. }
  436.  
  437. # Do an operation on tape device.
  438. # Usage: TapeOp tape-cmd
  439. function TapeOp {
  440.     typeset cDevs dev
  441.  
  442.     $debug && set -x
  443.     if [ -n "$REMOTE" ]; then
  444.     [ "$1" = rewind ] && print -rp "Rewinding..."
  445.     for dev in ${Devs[*]}; do
  446.         tail=${dev##*/}
  447.         set -A cDevs -- "${cDevs[@]}" "${dev%/*}/x${tail#*r}"
  448.     done
  449.     rcmd "$RemoteSys" $UserArg "
  450. for ControlDev in ${cDevs[*]}
  451. do
  452.     if [ -c \$ControlDev ]
  453.     then
  454.     tape $1 \$ControlDev
  455.     exit 0
  456.     fi
  457. done
  458. echo 'Could not find remote tape device for tape $1.  Tried: ${cDevs[*]}'
  459. exit 1"
  460.     else
  461.     [ "$1" = rewind ] && print -rp "Rewinding $ControlDev ..."
  462.     tape $1 "$ControlDev"
  463.     fi
  464. }
  465.  
  466. # Globals:
  467. # Uses filelist PrepList lname FINDOPTS PRESERVELISTS flist BLOCKSIZE REMOTE
  468. # RemoteSys UserArg rVerify SlowCmd PATH TapeSizeOpt Devs[]
  469. # Sets fLists[] nList NumGood GoodFS[]
  470. function Backup {
  471.     typeset fs=$1
  472.     typeset mountTail flist cpioCmd RCommand DDcmd dev
  473.  
  474.     if cd "$fs"; then
  475.     if [[ "$filelist" = *{}* ]]; then
  476.         [ "$fs" -ef / ] && mountTail=root || mountTail=${fs##*/}
  477.         flist="${filelist%%{\}*}$mountTail${filelist#*{\}}"
  478.     else
  479.         flist=$filelist
  480.     fi
  481.     [[ "$flist" != /* ]] && flist="$fs/$flist"
  482.     $PrepList || {
  483.         mkfiles "$flist" || {
  484.         print -ru2 "$lname: could not make temp file.  Exiting."
  485.         CleanExit 1
  486.         }
  487.         print -rp "Generating file list for $fs"
  488.         find . -mount ! \( -name '#*' -o -name '#*' -o -name '*
  489. *' -o -name core \) $FINDOPTS -print > $flist
  490.         [ "$PRESERVELISTS" = 1 ] || {
  491.         fLists[nList]=$flist
  492.         let nList+=1
  493.         }
  494.     }
  495.     print -rp "Backing up $fs"
  496.     cpioCmd="$CPIOPATH -aoC $((BLOCKSIZE*1024))"
  497.     if [ -n "$REMOTE" ]; then
  498.         RCommand="rcmd $RemoteSys $UserArg"
  499.         $cpioCmd | if $rVerify; then
  500.         if [ -z "$SlowCmd" ]; then
  501.             $RCommand "$TCPIOPATH -it > /dev/null"
  502.         else
  503.             # Add to PATH to increase chances of picking up 'slow'.
  504.             $RCommand \
  505.             "PATH=\$PATH:/usr/local/bin; $SlowCmd |
  506.             $TCPIOPATH -it > /dev/null"
  507.         fi
  508.         else
  509.         if [ "${#Devs}" = 1 ]; then
  510.             DDcmd="dd bs=${BLOCKSIZE}k of=${Devs[0]}"
  511.         else
  512.             DDcmd="
  513. for dev in ${Devs[*]}
  514. do
  515.     if [ -c \$dev ]
  516.     then
  517.     dd bs=${BLOCKSIZE}k of=\$dev
  518.     break
  519.     fi
  520. done"
  521.         fi
  522.         if [ -z "$SlowCmd" ]; then
  523.             $RCommand "$DDcmd"
  524.         else
  525.             $SlowCmd | $RCommand "$DDcmd"
  526.         fi
  527.         fi
  528.     elif [ -z "$SlowCmd" ]; then
  529.         $cpioCmd $TapeSizeOpt -O "$DEVICE"
  530.     else
  531.         $cpioCmd $TapeSizeOpt | $SlowCmd > "$DEVICE"
  532.     fi < "$flist"
  533.     $realControl && print -rp "$(TapeOp amount)"
  534.     let NumGood+=1
  535.     GoodFS[NumGood]=$fs
  536.     else
  537.     print -ru2 "Could not cd to $fs."
  538.     fi
  539. }
  540.  
  541. if [[ "$DEVICE" = *r+([!/]) ]]; then
  542.     dir=${DEVICE%/*}
  543.     tail=${DEVICE##*/}
  544.     ControlDev="$dir/x${tail#*r}"
  545.     $debug && print -ru2 "Generated control device name: $ControlDev"
  546.     realControl=true
  547. else
  548.     ControlDev=$DEVICE
  549.     realControl=false
  550. fi
  551.  
  552. if [ -z "$REMOTE" ]; then
  553.     [ ! -c "$ControlDev" ] && ControlDev=$DEVICE
  554.     $debug && print -ru2 "Final device name: $ControlDev"
  555. fi
  556.  
  557. if $TestTape; then
  558.     TapeOp status
  559.     exit $?
  560. fi
  561.  
  562. if [ -n "$NOLOG" ]; then
  563.     unset logfile
  564. else
  565.     if [ -z "$logfile" ]; then
  566.     TMP=/tmp
  567.     mktempfile fbackup. || {
  568.         print -ru2 -- "$lname: exiting."
  569.         exit 1
  570.     }
  571.     logfile=$mktempfile_ret
  572.     else
  573.     mkfiles -n -- "$logfile" || {
  574.         print -ru2 -- "$lname: exiting."
  575.         exit 1
  576.     }
  577.     logfile=${mkfiles_ret[0]}
  578.     fi
  579.     print -r -- "Writing status information to log file $logfile"
  580. fi
  581.  
  582. # duplicate fd 1 as 3 for logger, because writing to fd 1 in coprocess
  583. # writes to the coprocess output pipe.
  584. exec 3>&1
  585.  
  586. # Set up logger/timestamper as coprocess.
  587. # Use gawk if available to avoid repeatedly executing date.
  588. if type gawk > /dev/null; then
  589.     gawk -v "logfile=$logfile" '
  590.     {
  591.     time = systime()
  592.     if (time != otime) {
  593.         date = strftime("%D %T",time)
  594.         otime = time
  595.     }
  596.     line = date " " $0
  597.     print line > "/dev/stdout"
  598.     close("/dev/stdout")    # flush output 
  599.     if (logfile != "") {
  600.         print line >> logfile
  601.         # flush to logfile to; it may be being remotely monitored
  602.         close(logfile)
  603.     }
  604.     }' 1>&3 |&
  605. else
  606.     (
  607.     # SECONDS in subshell starts at 0; make sure oSec will initially be
  608.     # different than it.
  609.     typeset -i oSec=-1
  610.     while read line; do
  611.         # Only run date if the seconds have changed, to avoid executing
  612.         # date many times for bursts of log activity
  613.         if [ SECONDS -ne oSec ]; then
  614.         date=$(date "+%D %T")
  615.         oSec=SECONDS
  616.         fi
  617.         s="$date $line"
  618.         print -r -u3 -- "$s"
  619.         [ -n "$logfile" ] && print -r -- "$s" >> "$logfile"
  620.     done
  621.     ) |&
  622. fi
  623. Logger=$!
  624.  
  625. if $CheckOnly; then
  626.     set -A GoodFS -- "$@"
  627. else
  628.     [ -z "$NOREWIND" ] && TapeOp rewind
  629.     for fs; do
  630.     Backup "$fs"
  631.     done
  632. fi
  633.  
  634. TapeOp rewind
  635.  
  636. [ "$CHECK" = 1 ] || CleanExit 0
  637.  
  638. if [ -n "$REMOTE" ]; then
  639.     CheckCmd="
  640. for DEVICE in ${Devs[*]}
  641. do
  642.     [ -c \$DEVICE ] && break
  643. done
  644. [ -c \$DEVICE ] || {
  645.     echo 'Could not find remote tape device for tape check.  Tried: ${Devs[*]}'
  646.     exit 1
  647. }
  648. "
  649. fi
  650.  
  651. CheckCmd="$CheckCmd
  652. set -- ${GoodFS[*]}
  653. num=${#GoodFS[*]}
  654. while [ \$# -gt 0 ]
  655. do "'
  656.     extent=`expr $num - $# + 1`
  657.     echo "Checking extent $extent ($1)" '"
  658.     if $TCPIOPATH -it -C $((BLOCKSIZE*1024)) < "' $DEVICE > /dev/null
  659.     then
  660.     echo "Extent $extent ($1) OK"
  661.     sleep 5
  662.     else
  663.     break
  664.     fi
  665.     shift
  666. done'
  667.  
  668. if [ -n "$REMOTE" ]; then
  669.     rcmd "$RemoteSys" $UserArg "$CheckCmd"
  670. else
  671.     eval "$CheckCmd"
  672. fi 2>&1 | while read line; do print -rp -- "$line"; done
  673. #^^^ should be able to just do 1>&p, but it causes the logger to die (ksh bug?)
  674.     
  675. TapeOp rewind
  676. CleanExit 0
  677.